home *** CD-ROM | disk | FTP | other *** search
/ United Public Domain Gold 2 / United Public Domain Gold 2.iso / utilities / pu291.dms / pu291.adf / Clocks / SPClock.c < prev    next >
C/C++ Source or Header  |  1992-08-03  |  16KB  |  562 lines

  1. /*----------------------------------------------------------------------
  2.     SPClock
  3.     Version 2.1
  4.  
  5.     A simple sprite based clock that will stay in the upper left corner 
  6.     no matter which screen you switch to or where your screen scrolls
  7.     (in WB2.0).
  8.  
  9.     Copyright (C) 1991, Mark Waggoner
  10.     Permission is granted to distribute this as long as no charge beyond a
  11.     reasonable media charge is required.  Reasonable shall be defined to 
  12.     be the amount that Fred Fish charges or last charged for a disk of
  13.     software.
  14.  
  15.     You will probably want tabs set to 4 when editing this file
  16.  
  17.     Compiles with Manx C, 5.2a
  18.  
  19.     Note that this program uses special startup code found in start.a68
  20. ------------------------------------------------------------------------*/
  21. #include <functions.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <graphics/gfxbase.h>
  25. #include <graphics/view.h>
  26. #include <graphics/sprite.h>
  27. #include <libraries/dos.h>
  28. #include <libraries/dosextens.h>
  29. #include <exec/ports.h>
  30. #include <exec/tasks.h>
  31. #include <workbench/workbench.h>
  32. #include <workbench/startup.h>
  33. #include <workbench/icon.h>
  34. #ifndef SUPERHIRES
  35. #define SUPERHIRES 0x0020
  36. #endif
  37.  
  38. /* The sprite height */
  39. #define SPHEIGHT    10
  40.  
  41. /* Library Base Pointers */
  42.                 void    *SysBase = NULL;
  43. struct GfxBase             *GfxBase = NULL;
  44. struct IntuitionBase     *IntuitionBase = NULL;
  45.                 void    *DOSBase = NULL;
  46.                 void    *IconBase = NULL;
  47.  
  48. /* start.a68 saves the original stack pointer in _savsp */
  49. long _savsp;
  50.  
  51. /* The workbench startup message */
  52. struct WBStartup *WBenchMsg = NULL;
  53.  
  54. /* Option keywords */
  55. static char KWcolor1a[] = "COLOR1";
  56. static char KWcolor1b[] = "COLOR";
  57. static char KWcolor2a[] = "COLOR2";
  58. static char KWcolor2b[] = "SHADOW";
  59. static char KWcolor3a[] = "COLOR3";
  60. static char KWleft[]    = "LEFT";
  61. static char KWtop[]     = "TOP";
  62. static char KW24Hour[]  = "24HOUR";
  63. static char KWNoBlink[] = "NOBLINK";
  64. static char KWQuit[]     = "QUIT";
  65. static char KWStart[]     = "START";
  66.  
  67. /* a smaller (but probably slower) isspace than aztec's */
  68. #define isspace(c) (c == ' ' || c == '\t' | c == '\n')
  69.  
  70. /* The colors to use */
  71. static long    color1[3] = {15, 0, 0};
  72. static long    color2[3] = { 0, 0, 0};
  73. static long    color3[3] = { 0,15, 0};
  74.  
  75. /* The clock position */
  76. static long ClockX = -1,
  77.             ClockY = -1;
  78.  
  79. /* Switch options: */
  80. static UBYTE Hours24 = 0;
  81. static UBYTE Blink   = 1;
  82. static UBYTE StartOnly = 0;
  83.  
  84. /* The images are stored here */
  85. static    UWORD hourimage[SPHEIGHT+2][2];
  86. static    UWORD minuteimage[SPHEIGHT+2][2];
  87.  
  88. /* This data was generated from the "nums" file using nums2c.rexx 
  89.     The nums are copied into the images as appropriate */
  90. static UBYTE nums[13][2][10] = {
  91.     { {0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00},
  92.       {0x00,0x1C,0x84,0x84,0x84,0x84,0x84,0x84,0xC0,0x7C} }, /* 0 */
  93.     { {0x0C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x00},
  94.       {0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x18} }, /* 1 */
  95.     { {0x3E,0x63,0x03,0x03,0x0C,0x30,0x60,0x60,0x7F,0x00},
  96.       {0x00,0x1C,0xC4,0x04,0x02,0x08,0x00,0x80,0x80,0xFE} }, /* 2 */
  97.     { {0x3E,0x63,0x03,0x03,0x0E,0x03,0x03,0x63,0x3E,0x00},
  98.       {0x00,0x1C,0xC4,0x04,0x00,0x1C,0x04,0x04,0xC0,0x7C} }, /* 3 */
  99.     { {0x06,0x0E,0x16,0x26,0x46,0x7F,0x06,0x06,0x06,0x00},
  100.       {0x00,0x00,0x08,0x08,0x08,0x80,0xF8,0x08,0x08,0x0C} }, /* 4 */
  101.     { {0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x3E,0x00},
  102.       {0x00,0x9E,0x80,0x80,0x80,0xFC,0x04,0x04,0xC0,0x7C} }, /* 5 */
  103.     { {0x3E,0x63,0x60,0x60,0x7E,0x63,0x63,0x63,0x3E,0x00},
  104.       {0x00,0x1C,0x86,0x80,0x80,0x9C,0x84,0x84,0x40,0x7C} }, /* 6 */
  105.     { {0x7F,0x03,0x03,0x06,0x0C,0x18,0x18,0x18,0x18,0x00},
  106.       {0x00,0xFC,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x30} }, /* 7 */
  107.     { {0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x3E,0x00},
  108.       {0x00,0x1C,0x84,0x84,0xC0,0x1C,0x84,0x84,0xC0,0x7C} }, /* 8 */
  109.     { {0x3E,0x63,0x63,0x63,0x3F,0x03,0x03,0x63,0x3E,0x00},
  110.       {0x00,0x1C,0x84,0x84,0xC0,0x7C,0x04,0x84,0xC0,0x7C} }, /* 9 */
  111.     { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
  112.       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, /* space */
  113.     { {0x06,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x00},
  114.       {0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x0C} }, /* small 1 */
  115.     { {0x06,0x09,0x01,0x01,0x02,0x04,0x08,0x08,0x0F,0x00},
  116.       {0x00,0x06,0x1A,0x02,0x00,0x00,0x00,0x10,0x10,0x1E} }, /* small 2 */
  117. };
  118.  
  119. /* Message port and name used to indicate we are running */
  120. struct    MsgPort    *SPPort = NULL;
  121. static    char portname[] = "SPClock";
  122.  
  123. /* The sprites that we allocate */
  124. UWORD minute_spnum = -1,hour_spnum = -1;
  125. struct SimpleSprite hour_sprite,minute_sprite;
  126.  
  127. /*-------------------------------------------------------------------
  128.     Exit the program, freeing up global resources
  129. -------------------------------------------------------------------*/
  130. void
  131. exit(int code)
  132. {
  133.     long ret = code;
  134.  
  135.     if (minute_spnum != -1)
  136.         FreeSprite(minute_spnum);
  137.     if (hour_spnum != -1)
  138.         FreeSprite(hour_spnum);
  139.  
  140.     if (SPPort)
  141.         DeletePort(SPPort);
  142.  
  143.     if (GfxBase)     
  144.         CloseLibrary((struct Library *) GfxBase);
  145.     if (IntuitionBase) 
  146.         CloseLibrary((struct Library *) IntuitionBase);
  147.     if (DOSBase)
  148.         CloseLibrary((struct Library *) DOSBase);
  149.  
  150.     if (WBenchMsg) {
  151.         Forbid();
  152.         ReplyMsg((struct Message *)WBenchMsg);
  153.     }
  154.  
  155.     /* Get the original stack pointer back and return */
  156.     {
  157. #asm
  158.         move.l    %%ret,d0        ;pick up return exit code
  159.         move.l    __savsp#,sp        ;get back original stack pointer
  160.         rts                        ;and exit
  161. #endasm
  162.     }
  163. }
  164.  
  165. /*-------------------------------------------------------------------
  166.     See if SPClock is already running and signal it to stop
  167. -------------------------------------------------------------------*/
  168. void
  169. KillIfRunning(void) {
  170.     struct MsgPort *oldport;
  171.  
  172.     /* Check if we are already running */
  173.     Forbid();
  174.     if (oldport = FindPort(portname))
  175.         Signal(oldport->mp_SigTask,SIGBREAKF_CTRL_C);
  176.     Permit();
  177.     return;
  178. }
  179.  
  180. /*-------------------------------------------------------------------
  181.     See if we are already running by looking for a message port
  182.     named "SPClock".  If so, signal that process to stop.
  183.     If we signal another process to stop or can't open the message
  184.     port, we return an error code and the main program exits.
  185. -------------------------------------------------------------------*/
  186. int
  187. CheckIfRunning(void) {
  188.     struct MsgPort *oldport;
  189.     int error = 1;
  190.  
  191.     /* Check if we are already running */
  192.     Forbid();
  193.     if (oldport = FindPort(portname)) {
  194.         if (!StartOnly) 
  195.             Signal(oldport->mp_SigTask,SIGBREAKF_CTRL_C);
  196.     }
  197.     else            /* port doesn't exist, so add it and continue */
  198.     if (SPPort = CreatePort(portname,0)) error = 0;
  199.     Permit();
  200.     return(error);
  201. }
  202.  
  203. /*-------------------------------------------------------------------
  204.     Open the libraries that we will be using 
  205. -------------------------------------------------------------------*/
  206. int
  207. OpenLibraries(void) {
  208.     register int error = 1;
  209.     
  210.     /* Open up the libraries we need (look at all those evil gotos!) */
  211.     if (
  212.         ((DOSBase = OpenLibrary("dos.library",0L)) != NULL) &&
  213.         ((IntuitionBase = (struct IntuitionBase *) 
  214.             OpenLibrary("intuition.library",0L)) != NULL) &&
  215.         ((GfxBase = (struct GfxBase *) 
  216.             OpenLibrary("graphics.library",0L)) != NULL)
  217.         )
  218.         error = 0;
  219.     return(error);
  220. }
  221.  
  222. /*-------------------------------------------------------------------
  223.     Set the colors of the currently active viewport.  
  224.     This may make a mess of some screens.  
  225.     If so, and it bothers you, find a better algorithm
  226. -------------------------------------------------------------------*/
  227. void
  228. SetSpriteColors(void) {
  229.     int color_reg1,color_reg2;
  230.     struct ViewPort *vp;
  231.     WORD vp_max_pen;
  232.  
  233.     /* base color register numbers */
  234.     color_reg1 = ((hour_spnum & 0x06)*2)+16;
  235.     color_reg2 = ((minute_spnum & 0x06)*2)+16;
  236.  
  237.     vp = GfxBase->ActiView->ViewPort;
  238.     vp_max_pen = 1 << vp->RasInfo->BitMap->Depth;
  239.  
  240.     if ((color_reg1 > 16) && (color_reg1 > vp_max_pen)) {
  241.         SetRGB4(vp,color_reg1+1,color1[0],color1[1],color1[2]);
  242.         SetRGB4(vp,color_reg1+2,color2[0],color2[1],color2[2]);
  243.         SetRGB4(vp,color_reg1+3,color3[0],color3[1],color3[2]);
  244.     }
  245.     if ((color_reg2 != color_reg1) && (color_reg2 > vp_max_pen)) {
  246.         SetRGB4(vp,color_reg2+1,color1[0],color1[1],color1[2]);
  247.         SetRGB4(vp,color_reg2+2,color2[0],color2[1],color2[2]);
  248.         SetRGB4(vp,color_reg2+3,color3[0],color3[1],color3[2]);
  249.     }
  250. }
  251.  
  252. /*-------------------------------------------------------------------
  253.     Initialize the sprites
  254. -------------------------------------------------------------------*/
  255. int
  256. InitSprites(void) {
  257.     int i;
  258.  
  259.     /* Clear the sprite images */
  260.     for(i=0;i<SPHEIGHT+2;i++) 
  261.         hourimage[i][0] = hourimage[i][1] = 
  262.         minuteimage[i][0] = minuteimage[i][1] = 0;
  263.  
  264.     /* Try to get sprites 2 and 3, otherwise, take whatever is available */
  265.     hour_spnum = GetSprite(&hour_sprite,2L);
  266.     if (hour_spnum == -1) {
  267.         hour_spnum = GetSprite(&hour_sprite,-1L);
  268.         if (hour_spnum == -1) 
  269.             return(1);
  270.     }
  271.     minute_spnum = GetSprite(&minute_sprite,3L);
  272.     if (minute_spnum == -1) {
  273.         minute_spnum = GetSprite(&minute_sprite,-1L);
  274.         if (minute_spnum == -1) 
  275.             return(1);
  276.     }
  277.     SetSpriteColors();
  278.     return(0);
  279. }
  280.  
  281. /*-------------------------------------------------------------------
  282.     Skip past the next space delimited token in a string
  283. -------------------------------------------------------------------*/
  284. char *
  285. SkipToken(char *s) {
  286.     while(*s &&  isspace(*s)) s++;
  287.     while(*s && !isspace(*s)) s++;
  288.     return(s);
  289. }
  290.  
  291. /*-------------------------------------------------------------------
  292.     Check an option name for CLI parsing
  293. -------------------------------------------------------------------*/
  294. char *
  295. CheckOption(char *s,char *opt) {
  296.     int l,m;
  297.     char *t;
  298.  
  299.     l = strlen(opt);
  300.  
  301.     /* Find the length of the next word */
  302.     m = 0; t = s;
  303.     while(*t && !isspace(*t) && *t != '=') { t++; m++; }
  304.  
  305.     if (m!=l) 
  306.         s = NULL;
  307.     else
  308.     if (strncmp(s,opt,l))
  309.         s = NULL;
  310.     else {
  311.         s+=l;
  312.         /* Skip past an equal sign */
  313.         while(*s && isspace(*s)) s++;
  314.         if (*s == '=') s++;
  315.     }
  316.     return(s);
  317. }
  318.  
  319. /*-------------------------------------------------------------------
  320.     Extract a color specification from an argument
  321. -------------------------------------------------------------------*/
  322. char *
  323. ExtractColor(char *s,long color[3]) {
  324.         color[0]=atoi(s);
  325.         s = SkipToken(s);
  326.         color[1]=atoi(s);
  327.         s = SkipToken(s);
  328.         color[2]=atoi(s);
  329.         s = SkipToken(s);
  330.         return(s);
  331. }
  332.  
  333. /*-------------------------------------------------------------------
  334.     Parse workbench options
  335. -------------------------------------------------------------------*/
  336. void
  337. wb_parse(struct WBStartup *wbm)
  338. {
  339.     char *tool;
  340.     struct DiskObject *dob;
  341.  
  342.     CurrentDir(wbm->sm_ArgList->wa_Lock);
  343.  
  344.     if ((IconBase = OpenLibrary("icon.library", 0L)) == 0)
  345.         return;
  346.     if ((dob = GetDiskObject(wbm->sm_ArgList->wa_Name)) == 0)
  347.         goto NoDiskObj;
  348.  
  349.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor1a))
  350.         ExtractColor(tool,color1);
  351.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor1b))
  352.         ExtractColor(tool,color1);
  353.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor2a))
  354.         ExtractColor(tool,color2);
  355.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor2b))
  356.         ExtractColor(tool,color2);
  357.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWcolor3a))
  358.         ExtractColor(tool,color3);
  359.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWtop))
  360.         ClockY = atoi(tool);
  361.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWleft))
  362.         ClockX = atoi(tool);
  363.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KW24Hour))
  364.         Hours24 = 1;
  365.     if (tool = FindToolType((UBYTE **)dob->do_ToolTypes, KWNoBlink))
  366.         Blink = 0;
  367.  
  368.     FreeDiskObject(dob);
  369. NoDiskObj:
  370.     CloseLibrary(IconBase);
  371.     IconBase = NULL;
  372. }
  373.  
  374. /*-------------------------------------------------------------------
  375.     I parse the cli parameters before they get to main()
  376. -------------------------------------------------------------------*/
  377. void
  378. cli_parse(long alen, register char *aptr)
  379. {
  380.     char *s,*t;
  381.  
  382.     s = aptr;
  383.  
  384.     while(*s) {
  385.         while(*s && isspace(*s)) s++;
  386.         if ((t = CheckOption(s,KWcolor1a)) || (t = CheckOption(s,KWcolor1b)))
  387.             s = ExtractColor(t,color1);
  388.         else
  389.         if ((t = CheckOption(s,KWcolor2a)) || (t = CheckOption(s,KWcolor2b)))
  390.             s = ExtractColor(t,color2);
  391.         else
  392.         if ((t = CheckOption(s,KWcolor3a)))
  393.             s = ExtractColor(t,color3);
  394.         else
  395.         if (t = CheckOption(s,KWtop)) {
  396.             ClockY = atoi(t);
  397.             s = SkipToken(t);
  398.         }
  399.         else
  400.         if (t = CheckOption(s,KWleft)) {
  401.             ClockX = atoi(t);
  402.             s = SkipToken(t);
  403.         }
  404.         else
  405.         if (t = CheckOption(s,KW24Hour)) {
  406.             Hours24 = 1;
  407.             s = t;
  408.         }
  409.         else
  410.         if (t = CheckOption(s,KWNoBlink)) {
  411.             Blink = 0;
  412.             s = t;
  413.         }
  414.         else
  415.         if (t = CheckOption(s,KWQuit)) {
  416.             KillIfRunning();
  417.             s = t;
  418.             exit(0);
  419.         }
  420.         else
  421.         if (t = CheckOption(s,KWStart)) {
  422.             StartOnly = 1;
  423.             s = t;
  424.             exit(0);
  425.         }
  426.         else
  427.             s = SkipToken(s);
  428.     }
  429. }
  430.  
  431. /*-------------------------------------------------------------------
  432.     Here it is!! The main program!  Note that this is NOT called
  433.     like a normal C main().  This is more like the _main() routine.
  434.     You may not use any unix style standard i/o, or malloc, or
  435.     any floating point in this program!
  436. -------------------------------------------------------------------*/
  437. main(long alen,char *aptr) {
  438.     register struct Process *pr;
  439.     int i,o1,o2,o3,o4;
  440.     UWORD maxx;
  441.     ULONG sec,usec,lastsec = 0;
  442.     UWORD hours,minutes,pm;
  443.     ULONG line;
  444.  
  445.     if (OpenLibraries()) exit(103);        /* Open up the libraries */
  446.  
  447.     /* Figure out if we came from workbench or a CLI and process the
  448.         arguments accordingly */
  449.     pr = (struct Process *)FindTask(0L);
  450.     if (pr->pr_CLI)
  451.         cli_parse(alen, aptr);
  452.     else {
  453.         WaitPort(&pr->pr_MsgPort);
  454.         WBenchMsg = (struct WBStartup *)GetMsg(&pr->pr_MsgPort);
  455.  
  456.         if (WBenchMsg->sm_ArgList)
  457.             wb_parse(WBenchMsg);
  458.     }
  459.  
  460.     /* See if we are already running, kill other process and exit if so */
  461.     if (CheckIfRunning()) 
  462.         exit(0);
  463.  
  464.     /* Initialize the sprites.  Exit if unable to do so */
  465.     if (InitSprites())
  466.         exit(105);
  467.  
  468.     /* If no position specified, position the sprite near the right 
  469.        side, but not so it overlaps the usual screen gadgets */
  470.     /* Can you suggest a better way to do this? */
  471.     maxx = GfxBase->ActiView->ViewPort->DWidth;
  472.     if (GfxBase->ActiView->ViewPort->Modes & HIRES) maxx *= 2;
  473.  
  474.     if (ClockX < 0) ClockX = maxx - 48;
  475.     if (ClockY < 0) ClockY = 0;
  476.     hour_sprite.x = ClockX;
  477.     hour_sprite.y = ClockY;
  478.     hour_sprite.height = SPHEIGHT;
  479.  
  480.     minute_sprite.x = ClockX+16;
  481.     if (GfxBase->ActiView->Modes & SUPERHIRES)
  482.         minute_sprite.x = ClockX+8;
  483.     minute_sprite.y = ClockY;
  484.     minute_sprite.height = SPHEIGHT;
  485.  
  486.     /* Keep running until we get a BREAK signal */
  487.     while (!(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)) {
  488.         /* Find out what time it is */
  489.         CurrentTime(&sec,&usec);
  490.         sec = sec/60;            /* sec is now minutes */
  491.         if (sec != lastsec) {    /* Only update if the time has changed */
  492.  
  493.             /* Calculate the hours and minutes.  I keep 12 hour time! */
  494.             lastsec = sec;
  495.             minutes = sec % 60;
  496.             sec = sec/60;
  497.             hours = sec%24;
  498.             pm = 0;
  499.             if (hours*60+minutes > 720) pm = 1;
  500.             if (!Hours24) {
  501.                 if (hours > 12) hours -= 12;
  502.                 if (hours == 0) hours = 12;
  503.             }
  504.  
  505.             o1 = hours/10+10;
  506.             if (o1 > 12) o1 = 10;
  507.             o2 = hours%10;
  508.             o3 = minutes/10;
  509.             o4 = minutes%10;
  510.             for(i=0;i<SPHEIGHT;i++) {
  511.                 line =    (((USHORT) nums[o1][0][i]) << 27) | 
  512.                         (((USHORT) nums[o2][0][i]) << 19) |
  513.                         (((USHORT) nums[o3][0][i]) << 9) | 
  514.                         (((USHORT) nums[o4][0][i]) << 1);
  515.  
  516.                 hourimage[i+1][0]    = (line & 0xFFFF0000) >> 16;
  517.                 minuteimage[i+1][0]    = (line & 0x0000FFFF);
  518.  
  519.                 line =    (((USHORT) nums[o1][1][i]) << 27) | 
  520.                         (((USHORT) nums[o2][1][i]) << 19) |
  521.                         (((USHORT) nums[o3][1][i]) << 9) | 
  522.                         (((USHORT) nums[o4][1][i]) << 1);
  523.                 hourimage[i+1][1]    = (line & 0xFFFF0000) >> 16;
  524.                 minuteimage[i+1][1]    = (line & 0x0000FFFF);
  525.             }
  526.             /* Make the Colon and AM/PM indicator */
  527.             hourimage[3][0] |= 0x0002;
  528.             hourimage[7][0] |= 0x0002;
  529.             hourimage[4][1] |= 0x0004;
  530.             hourimage[8][1] |= 0x0004;
  531.  
  532.             if (pm && !Hours24) {
  533.                 hourimage[5][0] |= 0x0002;
  534.                 hourimage[5][1] |= 0x0002;
  535.                 hourimage[6][1] |= 0x0004;
  536.             }
  537.         }
  538.  
  539.         /* Make the blinking dots */
  540.         if (Blink) {
  541.             hourimage[3][0] ^= 0x0002;
  542.             hourimage[7][0] ^= 0x0002;
  543.             hourimage[4][1] ^= 0x0004;
  544.             hourimage[8][1] ^= 0x0004;
  545.         }
  546.  
  547.         /* Make sure this viewport has my colors set.  I would like
  548.            to not do this every time, but I'm not sure how to check
  549.            if another screen has moved to the front */
  550.         SetSpriteColors();
  551.  
  552.         /* Update the image */
  553.         ChangeSprite(NULL,&hour_sprite,(PLANEPTR) hourimage);
  554.         ChangeSprite(NULL,&minute_sprite,(PLANEPTR) minuteimage);
  555.  
  556.         /* Wait for 1 second */
  557.         Delay(50);
  558.     }
  559.  
  560.     exit(0);
  561. }
  562.